#include <iostream>
#include <string>
#include <jsoncpp/json/json.h>

#include <signal.h>

#include "../common/util.hpp"
#include "../common/log.hpp"
#include "./compiler.hpp"
#include "./runner.hpp"

namespace ns_compiler_runner
{
    using namespace ns_compiler;
    using namespace ns_runner;
    using namespace ns_util;
    using namespace ns_log;

    class CompilerAndRunner
    {
    public:
        // code > 0 : 进程收到了信号导致异常奔溃
        // code < 0 : 整个过程非运行报错(代码为空，编译报错等)
        // code = 0 : 整个过程全部完成
        static std::string CodeToDesc(int code, const std::string &file_name)
        {
            std::string desc;

            switch(code)
            {   
                case 0:
                    desc="编译运行成功";
                    break;
                case -1:
                    desc="提交的代码为空";
                    break;
                case -2:
                    desc="未知错误: 向src文件写入代码失败";
                    break;
                case -3:
                    // 编译错误
                    FileUtil::ReadFile(PathUtil::CompileError(file_name), &desc, true);
                    break;
                case -4:
                    desc="未知错误: Runner::Run执行失败";
                    break;
                case SIGABRT:
                    desc="内存超出范围";
                    break;
                case SIGXCPU:
                    desc="CPU超出使用";
                    break;
                case SIGFPE:
                    desc="浮点数溢出";
                    break;
                default:
                    desc = "未知: " + std::to_string(code);
                break;
            }

            return desc;
        }

        static void RemoveTempFile(const std::string &file_name)
        {
            // 源文件
            std::string file_src=PathUtil::Src(file_name);
            if(FileUtil::IsFileExist(file_src))
            {
                FileUtil::UnlinkFile(file_src);
            }
            // 编译错误文件
            std::string file_compile_error=PathUtil::CompileError(file_name);
            if(FileUtil::IsFileExist(file_compile_error))
            {
                FileUtil::UnlinkFile(file_compile_error);
            }
            // 可执行程序
            std::string file_exe=PathUtil::Exe(file_name);
            if(FileUtil::IsFileExist(file_exe))
            {
                FileUtil::UnlinkFile(file_exe);
            }
            // 运行标准输入
            std::string file_stdin=PathUtil::Stdin(file_name);
            if(FileUtil::IsFileExist(file_stdin))
            {
                FileUtil::UnlinkFile(file_stdin);
            }
            // 运行标准输出
            std::string file_stdout=PathUtil::Stdout(file_name);
            if(FileUtil::IsFileExist(file_stdout))
            {
                FileUtil::UnlinkFile(file_stdout);
            }
            // 运行标准错误
            std::string file_stderr=PathUtil::Stderr(file_name);
            if(FileUtil::IsFileExist(file_stderr))
            {
                FileUtil::UnlinkFile(file_stderr);
            }
        }

        /***********************************************
         * 
         * 编译+运行
         * 
         * 输入: const std::string &in_json
         * code: 提交的代码
         * input: 输入(读取)的数据
         * cpu_limit: 限制CPU运行资源
         * mem_limit: 限制内存大小
         * ...
         * 
         * 输出: std::string *out_json
         * status: 状态码
         * reason: 状态描述
         * stdout: 标准输出
         * stderr: 标准错误
         * ...
         * 
        ************************************************/
        static void Start(const std::string &in_json,std::string *out_json)
        {
                // 反序列化
                Json::Value in_root;
                Json::Reader reader;
                reader.parse(in_json,in_root);

                // 获取输入内容
                std::string in_code=in_root["code"].asString();
                std::string in_input=in_root["input"].asString(); // 目前不处理
                int cpu_limit=in_root["cpu_limit"].asInt();
                int mem_limit=in_root["mem_limit"].asInt();

                int status=0; // 输出状态码
                std::string reason; // 状态解释
                std::string file_name(""); // 唯一文件名
                int run_result=0; // 运行结果Runner::Run(file_name,cpu_limit,mem_limit)

                if(in_code.empty())
                {
                    status=-1; // 代码为空
                    goto END;
                }

                // 形成的文件名只具有唯一性，没有目录没有后缀
                // 毫秒级时间戳+原子性递增唯一值: 来保证唯一性
                file_name=FileUtil::GetUniqueFileName();

                // 生成src文件,并写入代码
                if( !FileUtil::WriteFile(PathUtil::Src(file_name),in_code) )
                {
                    status=-2; // 未知错误
                    goto END;
                }

                // 编译
                if( !Compiler::Compile(file_name) )
                {
                    // 返回状态码+编译错误原因
                    status=-3; // 编译失败
                    goto END;
                }

                run_result=Runner::Run(file_name,cpu_limit,mem_limit);
                if(run_result<0)
                {
                    status=-4; // 未知错误
                }
                else if(run_result>0)
                {
                    status=run_result; // 程序运行异常
                }
                else
                {
                    status=0; // 程序运行成功
                }
            END:
                Json::Value out_root;
                out_root["status"]=status;
                out_root["reason"]=CodeToDesc(status,file_name);

                if(0==status)
                {
                    std::string out_stdout;
                    FileUtil::ReadFile(PathUtil::Stdout(file_name),&out_stdout,true);
                    std::string out_stderr;
                    FileUtil::ReadFile(PathUtil::Stderr(file_name),&out_stderr,true);

                    out_root["stdout"]=out_stdout;
                    out_root["stderr"]=out_stderr;
                }
                
                // 序列化
                Json::FastWriter writer;
                *out_json=writer.write(out_root);

                RemoveTempFile(file_name);
        }
    };
}